package com.kzw.misc.web.servlet;

import com.kzw.core.mapper.Jackson;
import com.kzw.core.util.IdUtils;
import com.kzw.core.util.web.ResponseUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * 通用文件上传服务（不存储数据库），返回文件上传信息
 * */
@MultipartConfig(maxFileSize=1024*1024*20)	//单个文件不能超过20M
@WebServlet(name = "UploadServlet", urlPatterns = "/api/upload")
@SuppressWarnings({"serial", "unchecked"})
public class UploadServlet extends HttpServlet {
	
	// 禁止上传的文件类型: .jsp, .exe
	private String[] forbidSuffix = {"jsp", "exe"}; 
	private DateFormat df = new SimpleDateFormat("yyyyMM");
	private String category = "other";
	private List<String> allowList = null;
	

	/**
	 * 文件上传成功后，返回JSON（文件黑名单）
	 * 文件存储按类别、年月存储
	 * 	
	 * 	参数：{category:'undef', allow_suffix:[], params}
	 * 	code: 0，
	 * 	msg: 上传成功，
	 * 	data: [{url:'存储文件名', name:'', size:''}]
	 * */
	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		
		request.setCharacterEncoding("utf-8");
		response.setCharacterEncoding("utf-8");
		String params = request.getParameter("params");
		System.out.println(params);
		
		if(StringUtils.isNotBlank(params)) {
			Map<String, Object> map = Jackson.me().fromJson(params, Map.class);
			// 类别和允许的类型
			category = (String)map.get("category");
			allowList = (ArrayList<String>)map.get("allow_suffix");
		}
		
		// 存储路径
		String dir = request.getServletContext().getRealPath("/attachFiles");
		List<Map<String, Object>> list = new ArrayList<Map<String,Object>>();
		// 获取上传的文件集合
		Collection<Part> parts = request.getParts();
		Iterator<Part> it = parts.iterator();
		while(it.hasNext()) {
			Part part = it.next();
			String fname = part.getSubmittedFileName();
			if(fname==null || fname.equals("")) continue;
			
			// 是否允许上传
			if(!canUpload(fname, allowList)) continue;
			String ext = FilenameUtils.getExtension(fname);
			
			// 文件上传，文件名：类型+年月
			String path = category + "/" + df.format(new Date());
			File fileDir  = new File(dir, path).getCanonicalFile();
			if(!fileDir.exists()) {
				FileUtils.forceMkdir(fileDir);
			}
			
			// TODO: 可能需要存数据库，便于管理和查询
			String fid = IdUtils.getIncreaseIdByCurrentTimeMillis();
			String newfname = fid + "." + ext;
			part.write(fileDir.getCanonicalPath() + "/" + newfname);
						
			Map<String, Object> sub = new LinkedHashMap<String, Object>();
			sub.put("id", fid);	//新的文件名
			sub.put("name", fname); 	//原来的文件名
			sub.put("ext", ext);
			sub.put("size", part.getSize());
			sub.put("path", path + "/" + newfname);
			list.add(sub);
		}
		
		Map<String, Object> result = new LinkedHashMap<String, Object>();
		if(list.size() > 0) {
			result.put("code", 0);
			result.put("msg", "文件上传成功！");
			result.put("data", list);
		} else {
			result.put("code", 1);
			result.put("msg", "没有文件上传！");
		}
		
		String json = Jackson.me().toJson(result);
		ResponseUtils.renderJson(response, json);
	}

	/**
	 * 是否允许访问
	 * */
	public boolean canUpload(String fname, List<String> allowList) {
		// 文件是否有后缀名
		String ext = FilenameUtils.getExtension(fname);
		if(ext.equals("")) return false;
		
		// 如果是禁止访问类型
		if(Arrays.asList(forbidSuffix).contains(ext)) {
			return false;
		}
		
		// 如果没有设置allow_perm，则默认开放
		if(allowList==null || allowList.size()==0) {
			return true;
		}
		
		// 允许访问
		if(allowList.contains(ext)) {
			return true;
		}
				
		return false;
	}
	
}
